package com.example.texturedPoint;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;

public class MyRenderer implements GLSurfaceView.Renderer{

	public MyRenderer(Context context){
		/*
		 *in this new version we added a new context variable to our renderer
		 *so that we can load a texture, in a real app we wouldn't
		 *load texture in the render thread
		 */
		
		this.context = context;
		vertBuffer = ByteBuffer.allocateDirect(vertData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
		vertBuffer.put(vertData).position(0);
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		
		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
		GLES20.glUseProgram(sProgram);
		Matrix.setIdentityM(modelMatrix, 0);
		Matrix.translateM(modelMatrix, 0, 0.0f, 0.0f, -4.0f);
		
		vertBuffer.position(0);
		GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, vertBuffer);
		GLES20.glEnableVertexAttribArray(posHandle);
	
		//activate texture 0 in opengl
		GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
		/*set the texture we loaded to the active texture
		 * we tell opengl we will be using a 2d texture
		 * and provide a pointer to the image data
		 */
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imgHandle);
		/*then we pass this info into the fragment shader for texture lookup
		 * we pass in the handle to the fragment shader sampler2D with an offset of zero
		 */
		GLES20.glUniform1i(texHandle, 0);
		
		Matrix.multiplyMM(modViewProjMatrix, 0, viewMatrix, 0, modelMatrix, 0);
		Matrix.multiplyMM(modViewProjMatrix, 0, projMatrix, 0, modViewProjMatrix, 0);
	
		GLES20.glUniformMatrix4fv(MVPMatHandle, 1, false, modViewProjMatrix, 0);
		
		GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
		
		
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		mWidth = width;
		mHeight = height;
		GLES20.glViewport(0, 0, mWidth, mHeight);
		
		final float ratio = (float)mWidth/mHeight;
		final float left = -ratio;
		final float right = ratio;
		final float bottom = -1.0f;
		final float top = 1.0f;
		final float near = 3.0f;
		final float far = 10.0f;
		
		Matrix.frustumM(projMatrix, 0, left, right, bottom, top, near, far);
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		
		final float eyeX = 0.0f;
		final float eyeY = 0.0f;
		final float eyeZ = 3.0f;
		final float centerX = 0.0f;
		final float centerY = 0.0f;
		final float centerZ = 0.0f;
		final float upX = 0.0f;
		final float upY = 1.0f;
		final float upZ = 0.0f;
		
		Matrix.setLookAtM(viewMatrix, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
		
		vShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
		GLES20.glShaderSource(vShader, vCode);
		GLES20.glCompileShader(vShader);
		
		fShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
		GLES20.glShaderSource(fShader, fCode);
		GLES20.glCompileShader(fShader);
		
		sProgram = GLES20.glCreateProgram();
		GLES20.glAttachShader(sProgram, vShader);
		GLES20.glAttachShader(sProgram, fShader);
		GLES20.glLinkProgram(sProgram);
		
		posHandle = GLES20.glGetAttribLocation(sProgram, "aPos");
		MVPMatHandle = GLES20.glGetUniformLocation(sProgram, "uMVPMat");
		texHandle = GLES20.glGetUniformLocation(sProgram, "uTex0");
		
		//time to load our texture
		 textureBuffer = new int[1];
		 Bitmap img = null;
	     try {
	             img = BitmapFactory.decodeResource(context.getResources(), R.raw.texture);
	             GLES20.glGenTextures(1, textureBuffer, 0);
	             
	             GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureBuffer[0]);
	             GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
	             GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
                 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
                 GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
	             GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, img, 0);
	     } catch (Exception e){/*handle erros*/ }
	     img.recycle();
	     //pass the loaded texture data to our handle that we will use to reference this texture
	     imgHandle = textureBuffer[0];         
	}

	/*
	 * added a extra variable context to be able to load resources
	 * added handles for the fragment shader texture (texHandle), 
	 * a handle to the loaded image (imgHandle)
	 * and a buffer object for the texture we will load (textureBuffer);
	 */
	private Context context;
	private float[] modelMatrix = new float[16];
	private float[] viewMatrix = new float[16];
	private float[] projMatrix = new float[16];
	private float[] modViewProjMatrix = new float[16];
	private FloatBuffer vertBuffer;
	private int[] textureBuffer;
	private int vShader, fShader, sProgram, posHandle, texHandle, imgHandle, MVPMatHandle, mWidth, mHeight;
	
	
	private final String vCode =
			 "uniform mat4   uMVPMat;        \n"
			+"attribute vec4 aPos;           \n"
			+"void main(){                   \n"
			+" gl_PointSize = 450.0;         \n"
			+" gl_Position = uMVPMat * aPos; \n"
			+"}                              \n";
	
	/*
	 *we update our fragment shader to handle the texture lookup
	 *by adding a uniform sampler2D;
	 *we also use openGL built in variable gl_PointCoord
	 *that is an vertex shader output of the vertex position
	 */
	private final String fCode =
			 "precision mediump float;                  \n"
			+"uniform sampler2D uTex0;                  \n"
			+"void main(){                              \n"
			//+" gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0); \n"
			+" gl_FragColor = texture2D(uTex0, gl_PointCoord); \n"
			+"}                                         \n";
	
	private final float[] vertData = { 
			0.0f, 0.0f, 0.0f 
			};
}
